package com.cskaoyan.javase.object._2tostring;

/**
 * 方法的声明
 * Object类当中toString方法的，方法的声明很普通：
 *      public String toString()
 * 没有什么注意的地方，记住它有返回值，并且返回字符串String对象就可以了。
 *
 * API文档中解释
 * 关于toString方法的作用，在JDK文档中，有详细的说明，主要说以下四点：
 *      1.返回该对象（调用toString方法的对象）的字符串表示。
 *      2.通常，toString方法会返回一个"以文本方式表示"此对象的字符串。
 *              也就是说这个方法是为了能够一句话描述该对象
 *      3.结果应是一个简明但易于读懂的信息表达式。
 *      4.建议所有子类都重写此方法。
 *
 * 于是我们需要看一看，Object类当中它的默认实现，到底啥样:
 * 该方法在Object类当中的默认实现是:
 *      return getClass().getName() + "@" + Integer.toHexString(hashCode());
 * 分析如下:
 *      1."getClass().getName()" 获取该类型的全限定类名
 *      2.hashCode()也是Object类当中的一个方法,该方法是通过计算某个对象的内存地址得出一个十进制数
 *          这个十进制数可以看成该对象的十进制地址值
 *      3.Integer.toHexString(),将一个十进制整数,转换成十六进制的字符串
 *          所以:
 *          Integer.toHexString(hashCode()) 的结果是十六进制的地址值字符串
 *      连起来,该方法就是返回:
 *          "全限定类名 + @ + 十六进制地址值"
 * 通过以上分析,不难得出:
 *      在Java代码当中,如果直接打印引用"对象名",或者让引用参与字符串的拼接,实际上都是隐含调用了该类的toString方法
 *      打印和拼接的结果是该类的toString方法调用的结果
 *
 * 但是在很多情况下,查看地址值对我们了解对象帮助不大,一句话来描述这个对象
 * 我们更希望知道的是属性的取值,所以JDK文档中,建议我们自己重写这个方法.
 * 一般来说,绝大多数情形下,重写toString方法都是要打印属性的取值.
 *
 * 注意事项:
 *      1.toString方法的格式基本是固定的,建议不要手写,使用快捷键alt + insert来自动生成它
 *      2.toString方法的使用,建议自动生成,不要在里面加其他代码,尤其是业务代码不要加进去.
 *          合格的Java程序的某个类的toString方法,应该就是自动生成的默认格式
 *          debug模式下,程序运行过创建对象,使用引用操作对象等语句时,会自动调用toString方法
 *          所以toString方法如果乱写,就会导致一些奇怪的问题
 *      3.如果类中有（自定义）引用数据类型成员变量，也需要重写它的toString方法，不然就会打印地址值了。
 *
 *      4.toString 方法在很多时候都是隐式的被调用的,那么这个隐式调用需要直接写出来吗?或者说无所谓?
 *          为了避免空指针异常，打印对象名或对象名拼接字符串中的隐含调用的toString方法能不写出来就不要写出来
 *              不要画蛇添足。
 *          因为隐式调用不会空指针异常，但直接调用方法完全可能出现空指针异常。
 *
 *
 *
 * @since 11:05
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        /*Student s = new Student(18, 750);
        // System.out.println(s);
        // System.out.println(s + "hello world!");
        // System.out.println(s);
        System.out.println(s.score);*/
        Student s = new Student(18, 700, new Star("杨幂"));
        System.out.println(s);

        Student s2 = new Student(16, 600, null);
        System.out.println(s2);

    }
}

class Student {
    int age;
    double score;
    Star s;

    public Student(int age, double score, Star s) {
        this.age = age;
        this.score = score;
        this.s = s;
    }

    public Student(int age, double score) {
        this.age = age;
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", score=" + score +
                ", s=" + s  +
                '}';
    }
    /*@Override
    public String toString() {
        return "Student{" + "age = " + age + ", score = " + score + "}";
    }*/

    /*@Override
    public String toString() {
        score = 700;
        return "Student{" +
                "age=" + age +
                ", score=" + score +
                '}';
    }*/

   /* @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("Student{");
        sb.append("age=").append(age);
        sb.append(", score=").append(score);
        sb.append('}');
        return sb.toString();
    }*/
}

class Star {
    String name;

    public Star(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Star{" +
                "name='" + name + '\'' +
                '}';
    }
}